一.Lambda表达式概述
  面向对象编程思想关注如何创建一个类的对象,然后通过这个类对象调用类中的成员
  面向函数编程思想(函数式编程)更关注函数的使用或者说更关注最终实现目标,从而简化代码
  Lambda表示式就是为了实现函数式编程
二.Lambda表达式使用前提
  1.每个Lambda表达式都对应一个接口,并且只能对应接口类型
  2.该接口中只能含有一个抽象方法(JDK1.8以后,接口中含有默认方法,静态方法)
  JDK1.8及之后版本引入一个注解 @FunctionalInterface,检测该接口中是否只有一个抽象方法
  如果只有一个抽象方法编译通过,否则编译失败
三.Lambda格式和使用
	/**
	 * Lambda表达式格式与使用
	 *  interface 接口名{
	 *      返回值类型 方法名(形参列表);//接口中唯一一个抽象方法
	 *  }
	 *  一.完整格式
	 *     (参数类型1 参数名1,参数类型2 参数名2,...)->{语句1;语句2;...}
	 *     ():小括号中的 参数类型 参数名对应接口中抽象方法的形参列表
	 *        如果接口中的抽象方法形参列表为空,那么Lambda表达式的小括号就写 ()
	 *     {}:大括号中的语句相当于是实现了该接口中抽象方法的语句
	 *
	 */
	/**
	 * 二.简略格式
	 *   a.省略参数类型
	 *    (参数名)->{语句1;语句2;...} //()中可以省略参数类型,因为Lambda可以根据代码自动推断类型
	 *   b.省略()
	 *    参数名->{语句1;语句2;...}//当接口中的抽象方法的形参只有一个的时候,Lambda表达式可以省略()
	 *   c.省略{}
	 *    (参数类型1 参数名1,参数类型2 参数名2,....)-> 语句; //当重写接口中的抽象方法只有一条语句的时候,我们可以省略{}
	 *                                                  //省略{}的同时,也要省略return和;
	 */
四.Lambda表达式原理
	/**
	 * Lambda原理
	 *   类似于匿名内部类的原理
	 *   1.底层会Lambda表达式对应的接口的一个实现类
	 *     每个Lambda表达式对应一个实现类,重写目标对应该Lambda表达式{}中内容
	 *   2.当使用该Lambda表达式的时候,底层会创建该实现类对象
	 */
五.Java中已有的函数式接口
  a.Supplier
		/**
		 * Supplier接口:
		 *   适用于只获取结果不传递参数的操作
		 *
		 *  @FunctionalInterface
		 * public interface Supplier<T> {
		      T get();
		}

		Arrays类中的toString方法:
		static String toString(int[] a)
		将数组中的元素拼接成一个字符串,返回这个字符串
		 */
  b.Consumer接口
	/**
	 * Consumer接口
	 *   一般用于只传递参数消费(执行)而不获取结果的操作
	 *
	 *   @FunctionalInterface
	 * public interface Consumer<T> {
	 *
	 *    void accept(T t);
	 *  }
	 */
	/**
	 * Consumer接口中的默认方法
	 *   //当我们需要对同一个内容执行一个连续操作,可以使用andThen
	 *   //同时也可以利用andThen完成链式编程
	 *
	 *
	 *   default Consumer<T> andThen(Consumer<? super T> after) {
	 *         Objects.requireNonNull(after);
	 *         return (T t) -> { accept(t); after.accept(t); };
	 *   }
	 * 需求:要求首先打印一个字符串的长度,接着再去将这个字符串全部转换成大写后再打印
	 */
  c.Function接口
		/**
		 * Function接口
		 *    适用于既传递参数又获取执行结果的操作
		 *  @FunctionalInterface
		 * public interface Function<T, R> {
		 *    R apply(T t);
		 *  }
		 */
		/**
		 * Function接口
		 *    //为了完成链式编程,会将最后一个Function接口对应的Lambda的执行结果传递给倒数第二个Lambda表达式的参数,以此类推
		 *     default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
		 *         Objects.requireNonNull(before);
		 *         return (V v) -> this.apply(before.apply(v)); //f1.apply(f2.apply(13))
		 *     }
		 *
		 *     //为了完成链式编程,会将第一个Function接口对应的Lambda的执行结果传递给第二个Lambda表达式的参数,以此类推
		 *      default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
		 *         Objects.requireNonNull(after);
		 *         return (T t) -> after.apply(this.apply(t));//相当于f2.apply(f1.apply(t))
		 *     }
		 * 需求:将一个字符串的首字母转换成大写返回
		 *     首先截取出字符串的首字母
		 *     再将该首字母转换成大写
		 */
  d.Predicate
		/**
		 * Predicate接口中的默认方法
		 *     //相当于多个条件进行&&连接
		 *     //可以完成链式编程
		 *     //p1.and(p2).test(product)
		 *     default Predicate<T> and(Predicate<? super T> other) {
		 *         Objects.requireNonNull(other);
		 *         return (t) -> this.test(t) && other.test(t);//p1.test(t) && p2.test(t)
		 *     }
		 *     default Predicate<T> or(Predicate<? super T> other) {
		 *         Objects.requireNonNull(other);
		 *         return (t) -> test(t) || other.test(t);
		 *     }
		 *
		 *     default Predicate<T> negate() {
		 *         return (t) -> !test(t);
		 *     }
		 *
		 *  需求:
		 *    1.新建一个Product类,其中包含商品名称和商品的价格
		 *    2.新建一个List集合,存储四个商品
		 *    完成以下需求:
		 *     a.打印集合中价格<3000的商品信息
		 *     b.打印集合中商品名称包含联想并且价格>=3000的商品信息
		 *        商品名称要包含联想
		 *        商品价格>=3000
		 *     c.打印集合中商品名称包含华硕或者价格>7000的商品信息
		 *     d.打印集合中商品名称不包含联想的商品信息
		 */